home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Sample Code / Snippets / Development Tools & Languages / DTSCPlusLibrary / Sources / Application.cp < prev    next >
Encoding:
Text File  |  1993-01-14  |  18.6 KB  |  693 lines  |  [TEXT/MPS ]

  1. /* _________________________________________________________________________________________________________ //
  2.   Copyright © 1992-93 Apple Computer, Inc. All rights reserved.
  3.   Macintosh Developer Technical Support.C++ Macintosh Toolbox Framework.
  4.   Date: 11/6/92
  5.   Revision comments are at the end of this file.
  6.   ---
  7.   TApplication is an abstract base class, TBKApplication is a background only application class,
  8.   TGUIApplication is a window-based user application class. TQTApplication is a QuickTime aware application
  9.   class, TGXApplication is a Quick GX aware application class. Finally TQTAndGXApplication 
  10.   handles both QX and QT application work.
  11.   Application.cp contains the needed member functions for the classes defined above.
  12.   _________________________________________________________________________________________________________ */
  13.  
  14. // INCLUDE FILES
  15. #ifndef _APPLICATION_
  16. #include "Application.h"
  17. #endif
  18.  
  19.  
  20. // GLOBAL DATA AND FUNCTIONS
  21. TApplication* gApplication;                        // universal ptr to the framework
  22.  
  23. const short kDefaultNumMasters = 8;                // number of master pointers
  24. const OSType kAEResource = 'aedt';                // our AE binding resource
  25.  
  26. pascal OSErr AEDispatcher(AppleEvent* in,
  27.                           AppleEvent* out,
  28.                           long Command);        // AE Dispatcher
  29.  
  30.  
  31. // Global Functions
  32. pascal OSErr AEDispatcher(AppleEvent* in,
  33.                           AppleEvent* out,
  34.                           long Command)
  35. {
  36.     gApplication->DispatchAppleEvents(in, out, Command);// dispatch event back to the framework
  37.  
  38.     return noErr;
  39. }
  40.  
  41.  
  42. // _________________________________________________________________________________________________________ //
  43. // TApplication class member function implementations.
  44.  
  45. //    CONSTRUCTORS & DESTRUCTORS
  46.  
  47. #pragma segment Application 
  48. TApplication::TApplication()
  49. // Default constructor -- put together the basic environment (non-UI model).
  50. {
  51.     gApplication = this;                        // hook ptr to the global pointer
  52.  
  53.     // Default base class constructor, define fields to known initial values.
  54.     this->SetState(TApplication::kInit);        // set out first state
  55.     fSleepRegion = ::NewRgn();                    // define default sleep region for WaitNextEvent (NULL)
  56.     fSleepValue = TApplication::kBackgroundSleepValue;// default sleep value (ticks)
  57.     fEventMask = everyEvent;                    // default setting
  58.     fMoreMasters = kDefaultNumMasters;            // amount of more master calls
  59.  
  60.     this->InitializeMemory();                    // initialize memory
  61.     this->InstallAEHandler();                    // install our AE handler
  62. }
  63.  
  64.  
  65. #pragma segment Application 
  66. TApplication::~TApplication()
  67. // Default destructor -- empty for the time being.
  68. {
  69. }
  70.  
  71.  
  72. #pragma segment Application
  73. void TApplication::DoNextEvent()
  74. // Handle incoming events
  75. {
  76.     if (!::WaitNextEvent(fEventMask, &fEventRecord, fSleepValue, fSleepRegion))
  77.         fEventRecord.what = nullEvent;            // security issue
  78. }
  79.  
  80.  
  81. #pragma segment Application
  82. void TApplication::DoHighLevelEvent()
  83. // Handle high level events.
  84. {
  85.     fError = ::AEProcessAppleEvent(&fEventRecord);// handle primarly AEs
  86.     VASSERT(fError == noErr, ("Problems with AEProcessAppleEvent", fError));
  87. }
  88.  
  89. #pragma segment Application
  90. void TApplication::Start()
  91. // Start the application and let it run until we change the state to Quit.
  92. {
  93.     this->SetState(TApplication::kRun);            // set TApplication to run state
  94.  
  95.     while (fState != TApplication::kQuit)
  96.         this->DoEventLoop();
  97.     this->Quit();                                // out from the state, we will quit
  98. }
  99.  
  100.  
  101. #pragma segment Application
  102. void TApplication::Quit()
  103. // Quit the application, do any possible cleanup.
  104. {
  105. }
  106.  
  107.  
  108. //    CORE AE HANDLER METHODS
  109. #pragma segment Application
  110. void TApplication::InstallAEHandler()
  111. // Install our core Apple Event Handler that will dispatch the AEs back to the framework.
  112. {
  113.     Handle aedtResource = NULL;
  114.     SignedByte state;
  115.     Size tableSize;
  116.     AEEventTablePtr tablePtr;
  117.  
  118.     short numEntries = ::Count1Resources(kAEResource);// find out how many entries in the table
  119.     fError = ResError();
  120.     VASSERT(fError == noErr, ("Problems with Count1Resources = %d", fError));
  121.     
  122.     if(numEntries != 0)                                // we had 'aedt' resources
  123.     {
  124.         for (short i = 1; i <= numEntries; ++i)        // loop through the resources
  125.         {
  126.             aedtResource = ::Get1IndResource('aedt', i);// get resource
  127.             fError = ResError();
  128.             VASSERT(fError == noErr, ("Problems with Get1IndResource = %d", fError));
  129.             
  130.             state = ::HGetState(aedtResource);        // get the flags from the handle
  131.             ::HLockHi(aedtResource);                // and lock the handle high in memory
  132.  
  133.             tableSize = GetHandleSize(aedtResource);// get the size of the resource
  134.             fError = MemError();
  135.             VASSERT(fError == noErr, ("Problems with GetHandleSize = %d", fError));
  136.             
  137.             short elements = (short)(tableSize / sizeof(AEEventTable));// get N of elements in resource
  138.             tablePtr = (AEEventTablePtr) * aedtResource;// get ptr to the element
  139.  
  140.             // ••• Add the information into our fCommandTable as well for future lookups
  141.             for (short j = 0; j < elements; j++)    // go through the elements
  142.             {
  143.                 fError  = ::AEInstallEventHandler(tablePtr->theClass, tablePtr->theID, (EventHandlerProcPtr)AEDispatcher, tablePtr->theValue, false);
  144.                 VASSERT(fError == noErr, ("Problems with AEInstallEventHandler = %d", fError));
  145.                 ++tablePtr;
  146.             }
  147.             ::HSetState(aedtResource, state);        // restore state
  148.             ::ReleaseResource(aedtResource);        // release the resource
  149.         }
  150.     }
  151. }
  152.  
  153.  
  154. #pragma segment Application
  155. void TApplication::DispatchAppleEvents(AppleEvent* in,
  156.                                        AppleEvent* out,
  157.                                        long command)
  158. // Dispatch to the right Handler based on the command in the AE (refCon).
  159. {
  160.     switch (command)
  161.     {
  162.         case cQuitCommand:                        // a quit AE
  163.             this->HandleQuit(in, out, command);
  164.             break;
  165.         case cNewCommand:                            // a  new AE
  166.             this->HandleOpen(in, out, command);
  167.             break;
  168.         case cOpenCommand:                        // an open document AE
  169.             this->HandleOpenDocuments(in, out, command);
  170.             break;
  171.         case cPrintCommand:                        // a print AE
  172.             this->HandlePrint(in, out, command);
  173.             break;
  174.         default:                                        // hmm, something else then…
  175.             ASSERT(false, "\pProblem: We are dealing with an AE command that we have no handler for");
  176.             break;
  177.     }
  178. }
  179.  
  180.  
  181. #pragma segment Application
  182. OSErr TApplication::HandleQuit(AppleEvent*        /*in*/,
  183.                                AppleEvent*        /*out*/,
  184.                                long                /*refCon*/)
  185. // Our General Quit Handler. Set state to Quit and return.
  186. {
  187.     this->SetState(TApplication::kQuit);        // set state to Quit
  188.     return noErr;                                // need to have this due to AEHandler prototype
  189. }
  190.  
  191.  
  192. #pragma segment Application
  193. OSErr TApplication::HandleOpen(AppleEvent*        /*in*/,
  194.                                AppleEvent*        /*out*/,
  195.                                long                /*refCon*/)
  196. {
  197.     return errAEEventNotHandled;                // need to have this due to AEHandler prototype
  198. }
  199.  
  200. #pragma segment Application
  201. OSErr TApplication::HandleOpenDocuments(AppleEvent*/*in*/ ,
  202.                                         AppleEvent*/*out*/ ,
  203.                                         long    /*refCon*/)
  204. {
  205.     return errAEEventNotHandled;                // need to have this due to AEHandler prototype
  206. }
  207.  
  208. #pragma segment Application
  209. OSErr TApplication::HandlePrint(AppleEvent*        /*in*/,
  210.                                 AppleEvent*        /*out*/,
  211.                                 long            /*refCon*/)
  212. {
  213.     return errAEEventNotHandled;                // need to have this due to AEHandler prototype
  214. }
  215.  
  216.  
  217. //    STATE CHANGE METHODS
  218. #pragma segment Application
  219. void TApplication::SetState(TApplication::EState theState)
  220. {
  221.     fState = theState;
  222. }
  223.  
  224.  
  225. //    MAIN INTERFACE
  226. #pragma segment Application
  227. void TApplication::InitializeMemory()
  228. // Initialize issues dealing with memory use.
  229. {
  230.     ::MaxApplZone();                            // increase the zone
  231.     for (short i = 0; i < fMoreMasters; i++)    // bounce up the amount of master pointers
  232.         ::MoreMasters();
  233.     fError = MemError();
  234.     VASSERT(fError == noErr, ("Problems with MoreMasters = %d", fError));
  235. }
  236.  
  237.  
  238. // _________________________________________________________________________________________________________ //
  239. // TBKApplication class member function implementations
  240.  
  241. //    CONSTRUCTORS & DESTRUCTORS
  242.  
  243. #pragma segment Application 
  244. TBKApplication::TBKApplication()
  245. {
  246. }
  247.  
  248.  
  249. #pragma segment Application 
  250. TBKApplication::~TBKApplication()
  251. {
  252. }
  253.  
  254.  
  255. // _________________________________________________________________________________________________________ //
  256. // TGUIApplication class member function implementations
  257.  
  258. //    CONSTRUCTORS & DESTRUCTORS
  259.  
  260. #pragma segment Application 
  261. TGUIApplication::TGUIApplication()
  262. // Initialize the UI toolbox side.
  263. {
  264.     this->InitializeToolbox();                    // Initialize toolbox
  265.     TMenubar myMenubar;                            // handle my menu bar initialization
  266.  
  267.     fCursHandle = ::GetCursor(watchCursor);        // get the watch cursor resource
  268.     ::SetCursor(*fCursHandle);                    // change the cursor to the watch one
  269. }
  270.  
  271.  
  272. #pragma segment Application 
  273. TGUIApplication::~TGUIApplication()
  274. // Default destructor -- empty for the time being.
  275. {
  276. }
  277.  
  278.  
  279. #pragma segment Application
  280. void TGUIApplication::InitializeToolbox()
  281. // Initialize the toolbox requirements for a standard window based application.
  282. {
  283.     ::InitGraf(&qd.thePort);
  284.     ::InitFonts();
  285.     ::InitWindows();
  286.  
  287.     // _DON'T_ flush disk-inserted or os events or you'll be sorry! 
  288.     ::FlushEvents(everyEvent - diskMask - osMask, 0);
  289.  
  290.     // The following toolbox init calls are slightly overhead, but that's fine 
  291.     ::InitMenus();
  292.     ::TEInit();
  293.     ::InitDialogs((ResumeProcPtr)NULL);
  294.  
  295.     ::InitCursor();
  296. }
  297.  
  298. //    MAIN INTERFACE
  299. #pragma segment Application
  300. void TGUIApplication::Start()
  301. // Start the event loop handling.
  302. {
  303.     ::SetCursor(&qd.arrow);                        // OK, scursor back to to the arrow one
  304.     TApplication::Start();                        // call the inherited Start
  305. }
  306.  
  307.  
  308. //    EVENT HANDLING MEMBER FUNCTIONS
  309. #pragma segment Application
  310. void TGUIApplication::DoEventLoop()
  311. // This is the big event loop swith statement function.
  312. {
  313.     this->DoNextEvent();                        // get the next event record
  314.  
  315.     // This is the big switch statement, switch on events received
  316.     switch (fEventRecord.what)
  317.     {
  318.         case nullEvent:                            // we got a periodic null event
  319.             this->DoIdle();                        // call idle handler
  320.             break;
  321.  
  322.         case updateEvt:                            // we got an update event
  323.             this->DoWindowUpdate();                // call the window update member function
  324.             break;
  325.             
  326.         case diskEvt:                            // we got a disk insertion event (most likely formatting)
  327.             this->DoDiskEvent();
  328.             break;
  329.  
  330.         case mouseDown:                            // we got a mouse down event
  331.             // get the window where the mouse down happened, and do an action based on this
  332.             switch (::FindWindow(fEventRecord.where, &fCurrentWindow))
  333.             {
  334.                 case inSysWindow:                // It's a DA window, provide time for that.
  335.                     this->DoSystemTime();
  336.                     break;
  337.  
  338.                 case inDrag:                    // Move the window to a specific target.
  339.                     this->DoDragWindow();
  340.                     break;
  341.     
  342.                 case inGoAway:                    // Close the window.
  343.                     this->DoGoAwayWindow();        // do window close events
  344.                     // ••• Future, Send a Close command
  345.                     break;
  346.  
  347.                 case inContent:                    // handle click inside the window
  348.                     this->DoInWindowContent();
  349.                     break;
  350.  
  351.                 case inMenuBar:                    // handle menu bar clicks
  352.                     this->DoMenuCommand();
  353.                     break;
  354.                                     
  355.                 default:                        // ignore any other sane events for the time being
  356.                     break;
  357.             }
  358.  
  359.         case app4Evt:                            // we got a Multifinder event
  360.             switch ((unsigned long)fEventRecord.message >> TApplication::kHighByte)
  361.             {
  362.                 case TApplication::kSuspendResumeMessage:// suspend or deactivate message
  363.                     if ((fEventRecord.message & TApplication::kResumeMask) == 0)
  364.                         fSleepValue = TApplication::kBackgroundSleepValue;
  365.                     else                        // resume or activate message
  366.                         fSleepValue = TApplication::kForgroundSleepValue;
  367.                     break;
  368.             }
  369.             break;
  370.  
  371.         case kHighLevelEvent:
  372.             this->DoHighLevelEvent();            // handle our high level events (as AEs)
  373.             break;
  374.  
  375.         default:
  376.             break;
  377.     }
  378. }
  379.  
  380.  
  381. #pragma segment Application
  382. void TGUIApplication::DoIdle()
  383. // Handle idle time
  384. {
  385. }
  386.  
  387.  
  388. #pragma segment Application
  389. void TGUIApplication::DoSystemTime()
  390. // Handle DAs
  391. {
  392.     ::SystemClick(&fEventRecord, fCurrentWindow);
  393. }
  394.  
  395.  
  396. #pragma segment Application
  397. void TGUIApplication::DoDiskEvent()
  398. // Handle disk events (formatting, floppies inserted and so on).
  399. {
  400.     Point dlogPoint;
  401.     const short kDILeft = 40;
  402.     const short kDITop = 40;
  403.  
  404.     if (HiWrd(fEventRecord.message) != noErr)    // if no error indication
  405.     {
  406.         ::SetPt(&dlogPoint, kDILeft, kDITop);        // define the dlog box rect
  407.         fError = ::DIBadMount(dlogPoint, fEventRecord.message);// turn it over to the system
  408.         VASSERT(fError == noErr, ("Problems with DIBadMount = %d ", fError));
  409.     }
  410. }
  411.  
  412.  
  413. #pragma segment Application
  414. void TGUIApplication::DispatchAppleEvents(AppleEvent* in, AppleEvent* out, long command)
  415. // Take care of the GUI related Apple Events, and dispatch the rest to the TApplication level
  416. {
  417.     switch(command)
  418.     {
  419.         case cAboutCommand:        // Send an AE telling the system to display the About box
  420.             this->DoAboutBox();
  421.             break;
  422.         default:
  423.             TApplication::DispatchAppleEvents(in, out, command);
  424.             break;
  425.     }
  426. }
  427.  
  428.  
  429. #pragma segment Application
  430. void TGUIApplication::DoWindowUpdate()
  431. // Handle window update events.
  432. {
  433.     ::BeginUpdate((WindowPtr)fEventRecord.message);
  434.     ::SetPort((WindowPtr)fEventRecord.message);    // set port to the right grafport
  435.     this->Draw();                                            // call the window drawing part
  436.     ::EndUpdate((WindowPtr)fEventRecord.message);
  437. }
  438.  
  439.  
  440.  
  441. #pragma segment Application
  442. void TGUIApplication::DoDragWindow()
  443. // Handle the inDrag event.
  444. {
  445.     ::DragWindow(fCurrentWindow, fEventRecord.where, &qd.screenBits.bounds);
  446. }
  447.  
  448.  
  449. #pragma segment Application
  450. void TGUIApplication::DoGoAwayWindow()
  451. // Handle dogoAway events.
  452. {
  453.     ::TrackGoAway(fCurrentWindow, fEventRecord.where);
  454. }
  455.  
  456.  
  457. #pragma segment Application
  458. void TGUIApplication::DoInWindowContent()
  459. // Handle inWindow events.
  460. {
  461.     if (fCurrentWindow != ::FrontWindow())
  462.         ::SelectWindow(fCurrentWindow);            // make the window the foremost one
  463.     else
  464.         this->DoClick();                        // handle the click inside the foremost window
  465. }
  466.  
  467.  
  468.  
  469. //    MENU EVENTS
  470. #pragma segment Application
  471. void TGUIApplication::DoMenuCommand()
  472. // Handle menu mouse events.
  473. {
  474.     long aCommandNumber;
  475.  
  476.     this->AdjustUserInterface();                // first, make sure the menu entries are enabled/disabled
  477.  
  478.     fMenuResult = ::MenuSelect(fEventRecord.where);// get the selected menu (longword)    
  479.  
  480.     aCommandNumber = this->CalculateMenuCommand(fMenuResult);    // calculate our command number
  481.  
  482.     // We will handle the most typical menu entries here (Apple, Edit, File)
  483.     // and call DoCommand() with the rest of the possible commands.
  484.  
  485.     this->DoInternalMenus(aCommandNumber);        // handle internal menus (Apple)
  486.     this->DoCommand(aCommandNumber);            // handle external commands/menus
  487.  
  488.     ::HiliteMenu(0);                            // unhighlight what MenuSelect hilited and return
  489. }
  490.  
  491.  
  492. #pragma segment Application
  493. long TGUIApplication::CalculateMenuCommand(long menuEntry)
  494. // Calculate the command number based on the algorithm where the menu entry
  495. // is either a two-digit or a three-digit number, and where the first number
  496. // is the menu number.
  497. {
  498.     long command;
  499.     if (LoWrd(menuEntry) > 9)                    // use algorithm 2
  500.     {
  501.         command = (HiWrd(menuEntry) * 100) + LoWrd(menuEntry);
  502.     }
  503.     else                                                // use algorithm 1
  504.         command = (HiWrd(menuEntry) * 10) + LoWrd(menuEntry);
  505.     
  506.     return command;
  507. }
  508.  
  509.  
  510. #pragma segment Application
  511. void TGUIApplication::DoInternalMenus(long command)
  512. // Handle our internal menus, Apple, DAs and so on.
  513. {
  514.     Str255 daName;                                // our DA name
  515.     short daRefNum;                                // our DA refnum 
  516.  
  517.     switch (command)
  518.     {
  519.         case cAboutCommand:                        // our About box?
  520.             fMessenger.Send(kCoreEventClass, kAEAbout);
  521.             break;
  522.  
  523.         default:
  524.             if( HiWrd(fMenuResult) == mApple) // we have a DA?
  525.             {
  526.                 ::GetItem(GetMHandle(mApple), (short)LoWrd(fMenuResult), daName);
  527.                 daRefNum = ::OpenDeskAcc(daName);
  528.             }
  529.             break;
  530.     }
  531. }
  532.  
  533.  
  534. #pragma segment Application
  535. void TGUIApplication::DoCommand(long command)
  536. // Handle the default framework menus, post AE commands.
  537. {
  538.     switch(command)
  539.     {
  540.         case cQuitCommand:
  541.             fMessenger.Send(kCoreEventClass, kAEQuitApplication);
  542.             break;
  543.         
  544.         default:
  545.             TApplication::DoCommand(command);                    // let the underlying framework take a short
  546.             break;
  547.     }
  548. }
  549.  
  550.  
  551. //  AE HANDLING OVERRIDES
  552. #pragma segment Application
  553. OSErr TGUIApplication::HandleOpen(AppleEvent*        /*in*/,
  554.                                AppleEvent*            /*out*/,
  555.                                long                    /*refCon*/)
  556. {
  557.     this->DoCreateDocument();                    // Default behavior -- open one window ('document').
  558.     return noErr;                                // need to have this due to AEHandler prototype
  559. }
  560.  
  561.  
  562. //    DOCUMENT CREATION MEMBER FUNCTIONS
  563. #pragma segment Application
  564. void TGUIApplication::DoCreateDocument()
  565. // Create initially one window.
  566. {
  567.     TWindow * aWindow = new TWindow;
  568.     ASSERT(aWindow != NULL, "\pWe didn't create a TWindow");
  569.     
  570.     if(aWindow != NULL)
  571.         this->AddDocument(aWindow);
  572. }
  573.  
  574.  
  575. #pragma segment Application
  576. void TGUIApplication::AddDocument(TWindow* theDocument)
  577. // Add the document (Window) to an internal list of documents.
  578. {
  579.     fDocument = theDocument;
  580. }
  581.  
  582.  
  583. #pragma segment Application
  584. void TGUIApplication::DoCreateDocument(short windowID)
  585. // Create initially one window.
  586. {
  587.     TWindow * aWindow = new TWindow(windowID);
  588.     ASSERT(aWindow != NULL, "\pWe didn't create a TWindow");
  589.  
  590.     if(aWindow != NULL)
  591.         this->AddDocument(aWindow);
  592. }
  593.  
  594.  
  595. #pragma segment Application
  596. void TGUIApplication::Draw()
  597. // Define drawing instructions inside this method. Default dispatch
  598. // and draw the currently active document (window).
  599. {
  600.     fDocument->Draw();
  601. }
  602.  
  603.  
  604. #pragma segment Application
  605. void TGUIApplication::DoClick()
  606. // Handle a click inside a window, empty for the moment (need to override this one)
  607. {
  608. }
  609.  
  610.  
  611. #pragma segment Application
  612. void TGUIApplication::DoAboutBox()
  613. // Present our default about box, override for a better one!
  614. {
  615.     ASSERT(false, "\pThis is the Gamura framework! Override for a better about box");
  616. }
  617.  
  618.  
  619. #pragma segment Application
  620. void TGUIApplication::DoHelp()
  621. // This is the hook for a possible help system (something outside the help balloons)
  622. {
  623.     ASSERT(false, "\pYou triggered the help system, override for a real one!");
  624. }
  625.  
  626.  
  627. // _________________________________________________________________________________________________________ //
  628. // TQTApplication class member function implementations
  629.  
  630. //    CONSTRUCTORS & DESTRUCTORS
  631.  
  632. #pragma segment Application 
  633. TQTApplication::TQTApplication()
  634. // Initialize the QT specific parts.
  635. {
  636. }
  637.  
  638.  
  639. #pragma segment Application 
  640. TQTApplication::~TQTApplication()
  641. // Do any possible epilogue cleanup.
  642. {
  643. }
  644.  
  645.  
  646. // _________________________________________________________________________________________________________ //
  647. // TGXApplication class member function implementations
  648.  
  649. //    CONSTRUCTORS & DESTRUCTORS
  650.  
  651. #pragma segment Application 
  652. TGXApplication::TGXApplication()
  653. // Initialize the GX specific parts
  654. {
  655. }
  656.  
  657.  
  658. #pragma segment Application 
  659. TGXApplication::~TGXApplication()
  660. // Do any possible epilogue cleanup.
  661. {
  662. }
  663.  
  664.  
  665. // _________________________________________________________________________________________________________ //
  666. // TQTAndGXApplication class member function implementations
  667.  
  668. //    CONSTRUCTORS & DESTRUCTORS
  669.  
  670. #pragma segment Application 
  671. TQTAndGXApplication::TQTAndGXApplication()
  672. // Initialize the QT and GX specific parts.
  673. {
  674. }
  675.  
  676.  
  677. #pragma segment Application 
  678. TQTAndGXApplication::~TQTAndGXApplication()
  679. // Do any possible epilogue cleanup.
  680. {
  681. }
  682.  
  683.  
  684. // _________________________________________________________________________________________________________ //
  685.  
  686.  
  687. /*    Change History (most recent last):
  688.   No        Init.    Date        Comment
  689.   1        khs    11/6/92    New file
  690.   2        khs    1/14/93    Cleanup
  691. */
  692.  
  693.